﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone;
using Microsoft.Phone.Controls;
using System.Linq;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using Facebook;
using GeoFinderClientApp.Model;
using GeoFinderClientApp.Converters;
using System.Collections.ObjectModel;
using System.Threading;
using System.Device.Location;
using System.ComponentModel;
using System.Windows.Threading;
using GeoFinderClientApp.ServiceViewModelInterface;
using GPSPhoneEmulator;

namespace GeoFinderClientApp.Web
{
    public static class WebCore
    {
        public static FacebookClient _fbClient;

        public static readonly string APP_ID = "199258020095913";
        public static readonly string[] EXTENDED_PERMISSIONS = new[] { "user_checkins", "friends_checkins", "publish_checkins", "user_about_me", "user_photos", "user_videos", "publish_stream" }; //new[] { "user_about_me" };//, "read_friendlist" 
        
        public static Thread Task;

        private static Friend Me;
        private static ObservableCollection<Friend> FriendList;
        private static ViewModel.ViewModels vm = new ViewModel.ViewModels();
        private static PushContext pushContext;
        
        public static event EventHandler<LoginEventArgs> FacebookDataRecived;
        public static event EventHandler<LoginEventArgs> FacebookFailure;
        public static event EventHandler<LoginEventArgs> SubscriptionCompleted;
        public static event EventHandler<LoginEventArgs> PushFail;


        private static event EventHandler<LoginEventArgs> FacebookStart;
        private static event EventHandler<LoginEventArgs> GPSUpdate;

        private static bool FBLock = false;

        public static bool LoggedIn { get; set; }
        private static bool firstTime = true;
        private static bool PushSettingDesync = false;
        private static bool toSubscribe = true;
        private static Dispatcher Dispatcher;
        private static GPSEmulator GPS;


        static bool isSubscribing = false;

        internal const string ServerAddress = "http://localhost:1272";

        private const string ChannelName = "GeoFinder.Service.GeoFinder";
        private const string ServiceName = "GeoFinder";

        private static readonly Uri[] AllowedDomains =
            {
                new Uri(ServerAddress)
            };


        public static void FirstTime(Dispatcher dispatcher)
        {
            if (firstTime)
            {
                Dispatcher = dispatcher;
                FacebookStart += new EventHandler<LoginEventArgs>(WebCore_FacebookStart);
                _fbClient.GetCompleted += new EventHandler<FacebookApiEventArgs>(_fbClient_GetCompleted);
                GPSUpdate += new EventHandler<LoginEventArgs>(WebCore_GPSUpdate);
                pushContext = new PushContext(ChannelName, ServiceName, AllowedDomains, dispatcher);
                GPS = new GPSEmulator();
                GPS.Start();
                firstTime = false;
            }
            FacebookStart(null, null);
        }

        //static void WebCore_PushOk(object sender, LoginEventArgs e)
        //{
        //    FacebookStart(null, null);
        //}


        public static void MainMethod()
        {
            while (true)
            {
                Thread.Sleep(new TimeSpan(0, 0, 30));
                vm.GetTimeOutOptions();
                if (vm.TimeOutOptions[0].AutomaticRefreshMode)
                {
                    RefreshAll();
                }
            }
        }

        public static void RefreshAll()
        {
            try
            {
                if (!FBLock)
                {
                    FacebookStart(null, null);
                }
            }
            catch { }
        }

        static void WebCore_GPSUpdate(object sender, LoginEventArgs e)
        {
            try
            {
                vm.GetMe();
                vm.Me.Position = GPS.Position.Location;
                vm.SaveMe();

                var pushService = _pushService;

                if (_pushService == null)
                {
                    pushService = new ServiceViewModelInterface.GeoFinderClient();
                    _pushService = pushService;
                }

                pushService.UpdateGPSCompleted += new EventHandler<UpdateGPSCompletedEventArgs>(pushService_UpdateGPSCompleted);


                if (_pushService.State == System.ServiceModel.CommunicationState.Opened)
                {
                    pushService.UpdateGPSAsync(Me.ID, toSQLString(Me.Position));
                }
            
            }
            catch { }
        }

        static void pushService_UpdateGPSCompleted(object sender, UpdateGPSCompletedEventArgs e)
        {
            _pushService.UpdateGPSCompleted -= pushService_UpdateGPSCompleted;

            if (_pushService != null && _pushService.State == System.ServiceModel.CommunicationState.Opened)
            {
                _pushService.CloseAsync();
            }

            vm.GetSavedFriends();

            if (vm.AllFriends.Count < 1)
            {
                FacebookDataRecived("data recived", null);
                return;
            }

            foreach (var item in e.Result)
            {
                var str = item.Split(new char[] { '#' });
                var id = long.Parse(str[0]);
                var location = toGeoCoord(str[1]);
                try
                {
                    vm.AllFriends.First(f => f.ID == id).Position = location;
                }
                catch (Exception){}
            }

            vm.SaveFriends();

            FacebookDataRecived("data recived", null);

        }

        private static GeoCoordinate toGeoCoord(string coord)
        {
            var tmp = coord.Split(new char[] { ';' });
            var lat = double.Parse(tmp[0]);
            var lon = double.Parse(tmp[1]);
            return new GeoCoordinate(lat, lon);
        }

        private static string toSQLString(GeoCoordinate coord)
        {
            return coord.Latitude + ";" + coord.Longitude;
        }

         //At this point we have an access token so we can get information from facebook
        static void WebCore_FacebookStart(object sender, LoginEventArgs e)
        {
            if (FBLock) return;
            FBLock = true;

            _fbClient.GetAsync("/me/friends");

            //MessageBox.Show("Facebook Login succeded");

        }

        static void _fbClient_GetCompleted(object sender, FacebookApiEventArgs e)
        {
            if (e.Error == null)
            {
                var result = (IDictionary<string, object>)e.GetResultData();
                //FriendsManager.
                //var names = (from person in list select person["name"]).ToList();
                if (result == null)
                {
                    FBLock = false;
                    FacebookFailure("error downloading friends list", null);
                    return;
                }

                try
                {
                    var friends = result.ConvertFriendsData();
                    
                    FriendList = new ObservableCollection<Friend>();
                    foreach (var item in friends)
                    {
                        FriendList.Add(item);
                    }
                    vm.AllFriends = FriendList;
                    vm.SaveFriends();
                    _fbClient.GetAsync("/me");
                }
                catch (Exception)
                {
                    Me = result.ConvertMeData();
                    
                    vm.Me = Me;
                    vm.SaveMe();
                                        
                    FBLock = false;

                    if (toSubscribe)
                    {
                        toSubscribe = false;
                        InternalLogin();
                    }
                    else
                    {
                        UpdateFriends();
                    }

                }
            }
            else
            {
                FBLock = false;
                MessageBox.Show(e.Error.Message);
                FacebookFailure(e.Error.Message, null);
            }
        }

        private static void InternalLogin()
        {
            var pushContext = PushContext.Current;
            pushContext.Connect(c => RegisterClient(c.ChannelUri));
        }

        private static void RegisterClient(Uri channelUri)
        {
            // Register the URI with 3rd party web service.
            try
            {
                var pushService = new ServiceViewModelInterface.GeoFinderClient();
                vm.GetMe();
                vm.getAllOptions();

                _pushService = pushService;

                isSubscribing = true;

                pushService.UpdateFacebookFriendsCompleted += new EventHandler<UpdateFacebookFriendsCompletedEventArgs>(stop_events_return);
                pushService.UpdateSearchingAreaCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdateFriends);
                pushService.UpdatePushSettingsCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdateSearchingArea);
                pushService.SubscribeCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdatePushSettings);

                pushService.SubscribeAsync(vm.Me.ID, channelUri.ToString(), vm.Me.ID);
            }
            catch (Exception)
            {

                PushFail(null, null);

            }
        }

        private static ServiceViewModelInterface.GeoFinderClient _pushService = null;






        static void stop_events_return(object sender, UpdateFacebookFriendsCompletedEventArgs e)
        {
            isSubscribing = false;
            //_pushService.CloseAsync();
            _pushService.UpdateFacebookFriendsCompleted -= stop_events_return;
            _pushService.UpdatePushSettingsCompleted -= pushService_UpdateSearchingArea;
            _pushService.UpdateSearchingAreaCompleted -= pushService_UpdateFriends;
            _pushService.SubscribeCompleted -= pushService_UpdatePushSettings;
            SubscriptionCompleted(null, null);
            //_pushService = null;
        }

        static void pushService_UpdateFriends(object sender, AsyncCompletedEventArgs e)
        {
            UpdateFriends_LOGIN();
        }

        static void pushService_UpdateSearchingArea(object sender, AsyncCompletedEventArgs e)
        {
            UpdateSearchingAreaOptions_LOGIN();
        }

        static void pushService_UpdatePushSettings(object sender, AsyncCompletedEventArgs e)
        {
            UpdatePushOptions_LOGIN();
        }

        //public static void UpdateBlackAndWhite_LOGIN()
        //{
        //    try
        //    {
        //        if (_pushService == null)
        //        {
        //            var pushService = new ServiceViewModelInterface.GeoFinderClient();
        //            _pushService = pushService;
        //        }
        //        vm.GetMe();
        //        vm.GetSavedFriends();

        //        var zipped = new ObservableCollection<long>();
        //        foreach (var friend in vm.AllFriends)
        //        {
        //            long id = friend.IsWhiteVisible ? friend.ID * 10 : (friend.ID * 10) + 1;
        //            zipped.Add(id);
        //        }

        //        //pushService.SetBlackAndWhiteFacebookFriendsCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_SetBlackAndWhiteFacebookFriendsCompleted);

        //        _pushService.SetBlackAndWhiteFacebookFriendsAsync(Me.ID, zipped);
        //    }
        //    catch (Exception)
        //    {
        //        PushFail(null, null);
        //    }
        //}

        public static void UpdateBlackAndWhite()
        {
            try
            {
                var pushService = new ServiceViewModelInterface.GeoFinderClient();
                _pushService = pushService;
                vm.GetMe();
                vm.GetSavedFriends();

                var zipped = new ObservableCollection<long>();
                foreach (var friend in vm.AllFriends)
                {
                    long id = friend.IsWhiteVisible ? friend.ID * 10 : (friend.ID * 10) + 1;
                    zipped.Add(id);
                }

                pushService.SetBlackAndWhiteFacebookFriendsCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_SetBlackAndWhiteFacebookFriendsCompleted);

                pushService.SetBlackAndWhiteFacebookFriendsAsync(Me.ID, zipped);
            }
            catch (Exception )
            {
                PushFail(null, null);
            }
        }

        static void pushService_SetBlackAndWhiteFacebookFriendsCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _pushService.UpdatePushSettingsCompleted -= pushService_SetBlackAndWhiteFacebookFriendsCompleted;
        }

        public static void UpdateSearchingAreaOptions_LOGIN()
        {
            try
            {
                if (_pushService == null)
                {
                    var pushService = new ServiceViewModelInterface.GeoFinderClient();
                    _pushService = pushService;
                }
                vm.GetMe();
                vm.GetSearchingAreaOptions();

                //pushService.UpdateSearchingAreaCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdateSearchingAreaCompleted);

                _pushService.UpdateSearchingAreaAsync(vm.Me.ID, vm.SearchingAreaOptions[0].SearchingArea);
            }
            catch (Exception)
            {
                PushFail(null, null);
            }
        }

        public static void UpdateSearchingAreaOptions()
        {
            try
            {
                var pushService = new ServiceViewModelInterface.GeoFinderClient();
                _pushService = pushService;
                vm.GetMe();
                vm.GetSearchingAreaOptions();

                pushService.UpdateSearchingAreaCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdateSearchingAreaCompleted);

                pushService.UpdateSearchingAreaAsync(vm.Me.ID, vm.SearchingAreaOptions[0].SearchingArea);
            }
            catch (Exception)
            {
                PushFail(null, null);
            }
        }

        static void pushService_UpdateSearchingAreaCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _pushService.UpdateSearchingAreaCompleted -= pushService_UpdateSearchingAreaCompleted;
        }

        public static void UpdatePushOptions_LOGIN()
        {
            try
            {
                if (_pushService == null)
                {
                    var pushService = new ServiceViewModelInterface.GeoFinderClient();
                    _pushService = pushService;
                }
                vm.GetMe();
                vm.getAllOptions();

                _pushService.UpdatePushSettingsAsync(
                    vm.Me.ID,
                    vm.PushOptions[(int)PushType.Push].IsEnabled,
                    vm.PushOptions[(int)PushType.Toast].IsEnabled,
                    vm.PushOptions[(int)PushType.Tile].IsEnabled,
                    vm.PushOptions[(int)PushType.Raw].IsEnabled);
            }
            catch (Exception)
            {
                PushFail(null, null);
            }
        }

        public static void UpdatePushOptions()
        {
            try
            {
                var pushService = new ServiceViewModelInterface.GeoFinderClient();
                _pushService = pushService;
                vm.GetMe();
                vm.getAllOptions();

                pushService.UpdatePushSettingsCompleted += new EventHandler<AsyncCompletedEventArgs>(pushService_UpdatePushSettingsCompleted);

                pushService.UpdatePushSettingsAsync(
                    vm.Me.ID,
                    vm.PushOptions[(int)PushType.Push].IsEnabled,
                    vm.PushOptions[(int)PushType.Toast].IsEnabled,
                    vm.PushOptions[(int)PushType.Tile].IsEnabled,
                    vm.PushOptions[(int)PushType.Raw].IsEnabled);
            }
            catch (Exception )
            {
                PushFail(null, null);
                PushSettingDesync = true;
            }
        }

        static void pushService_UpdatePushSettingsCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _pushService.UpdatePushSettingsCompleted -= pushService_UpdatePushSettingsCompleted;
        }

        public static void UpdateFriends_LOGIN()
        {
            try
            {
                if (_pushService == null)
                {
                    var pushService = new ServiceViewModelInterface.GeoFinderClient();
                    _pushService = pushService;
                }
                vm.GetMe();
                vm.GetFriends();

                _pushService.UpdateFacebookFriendsCompleted += new EventHandler<UpdateFacebookFriendsCompletedEventArgs>(service_UpdateFacebookFriendsCompleted);
             
                var fid = (from friend in vm.AllFriends select friend.ID).ToObservableCollection<long>();

                _pushService.UpdateFacebookFriendsAsync(vm.Me.ID, fid);
            }
            catch (Exception )
            {
                PushFail(null, null);
            }
        }

        public static void UpdateFriends()
        {
            try
            {
                var service = new ServiceViewModelInterface.GeoFinderClient();
                _pushService = service;
                vm.GetMe();
                vm.GetFriends();

                service.UpdateFacebookFriendsCompleted += new EventHandler<UpdateFacebookFriendsCompletedEventArgs>(service_UpdateFacebookFriendsCompleted);

                var fid = (from friend in vm.AllFriends select friend.ID).ToObservableCollection<long>();

                service.UpdateFacebookFriendsAsync(vm.Me.ID, fid);
            }
            catch (Exception )
            {
                PushFail(null, null);
            }
        }

        static void service_UpdateFacebookFriendsCompleted(object sender, UpdateFacebookFriendsCompletedEventArgs e)
        {

            var white = (from wcli in e.Result where wcli % 10 == 0 select wcli / 10).ToList<long>();
            var black = (from wcli in e.Result where wcli % 10 != 0 select wcli / 10).ToList<long>();

            vm.GetFriends();
            var nw = white.Concat(black);
            var newFriends = vm.AllFriends.Where(f => nw.Contains(f.ID)).ToList<Friend>();
            newFriends.ForEach(f => f.IsWhiteVisible = white.Contains(f.ID));
            vm.AllFriends = newFriends.ToObservableCollection<Friend>();
            vm.SaveFriends();

            _pushService.UpdateFacebookFriendsCompleted -= service_UpdateFacebookFriendsCompleted;

            GPSUpdate(null, null);
        }    
    }

    public class LoginEventArgs : EventArgs
    {
        public Exception Exception { get; private set; }

        public LoginEventArgs(Exception exception = null)
        {
            Exception = exception;
        }
    }
}
